package com.usf.jprovider.tools;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.usf.jprovider.constants.Constants;
import com.usf.jprovider.exception.XMLTagNotFundException;

public final class XMLTools {

	public static Document createDocument() throws ParserConfigurationException{
		DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
		DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
		return dBuilder.newDocument();
	}
	public static Document loadDocument(String path) throws ParserConfigurationException, SAXException, IOException{
		File file = new File(path);
		DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
		DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
		return dBuilder.parse(file);
	}
	public static void saveDocument(Document document, String path) throws TransformerException{
			TransformerFactory factory = TransformerFactory.newInstance();
			Transformer transformer = factory.newTransformer();
			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
			StreamResult result = new StreamResult(new File(path));
			DOMSource source = new DOMSource(document);
			transformer.setParameter(OutputKeys.INDENT, "yes");
			transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
			transformer.transform(source, result);
//			StreamResult result2 = new StreamResult(System.out);
//			transformer.transform(source, result2);
	}
	
	public static Node searchChildNode(Node parent, String tag) throws XMLTagNotFundException {
		NodeList list = parent.getChildNodes();
		for(int i=0; i<list.getLength(); i++){
			Node node = list.item(i);
			if(node.getNodeName().equals(tag)) return node;
		}
		throw new XMLTagNotFundException(tag);
	}
	
	public static List<Node> searchChildNodes(Node parent, String tag){
		NodeList list = parent.getChildNodes();
		List<Node> nodes = new ArrayList<Node>();
		for(int i=0; i<list.getLength(); i++){
			Node node = list.item(i);
			if(node.getNodeName().equals(tag))
				nodes.add(node);
		}
		return nodes;
	}
	
	public static Node searchNode(Document document, String tagPath) throws XMLTagNotFundException {
		String[] tags = tagPath.split(Constants.MEMBER_SEPARATOR_SPLIT);
		Node current = document.getDocumentElement();
		if(!current.getNodeName().equals(tags[0])) throw new XMLTagNotFundException(tags[0], tagPath);
		for(int i=1; i<tags.length; i++){
			current = searchChildNode(current, tags[i]);
			if(current == null) 
				throw new XMLTagNotFundException(tags[i], tagPath);
		}
		return current;
	}

	public static String[] searchNodes(Document document, String tagPath) throws DOMException, XMLTagNotFundException {//TODO Implement
		String[] values = new String[1];
		values[0] = searchNode(document, tagPath).getTextContent();
		return values;
	}
	
	public static <T> T load(String path, Class<T> klass) throws JAXBException{
		File file = new File(path);
		JAXBContext jaxbContext = JAXBContext.newInstance(klass);
		Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
		return klass.cast(jaxbUnmarshaller.unmarshal(file));
	}
	public static void save(Object object, String path) throws IOException, JAXBException{
			FileWriter file = new FileWriter(path);
			JAXBContext jaxbContext = JAXBContext.newInstance(object.getClass());
			Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
			jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
			jaxbMarshaller.marshal(object, file);
	}
	public static String toXML(Object object) throws JAXBException{
		StringWriter writer = new StringWriter();
		JAXBContext jaxbContext = JAXBContext.newInstance(object.getClass());
		Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
		jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
		jaxbMarshaller.marshal(object, writer);
		return writer.toString();
	}	
}
